package com.xyy.saas.payment.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xyy.saas.payment.adpater.xydLoan.core.constants.XydCreditLoanConstants;
import com.xyy.saas.payment.adpater.xydLoan.core.dto.XydNotifyAuthCreditDto;
import com.xyy.saas.payment.adpater.xydLoan.core.dto.XydNotifyCancelRepaymentDto;
import com.xyy.saas.payment.adpater.xydLoan.core.req.*;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.payment.core.service.XydCreditLoanService;
import com.xyy.saas.payment.trace.AlarmService;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.xydSign.XydSignUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @author wangzeqi
 */
@Slf4j
@RestController
@RequestMapping(value = {"/api/platform/xyd"})
@DependsOn("apolloUtil")
public class XydCreditLoanThirdController extends PlatformController {

    private static final String XYD_RESPONSE_PUBLIC_KEY = ApolloUtil.getProperty("xydLoad.client.response.publicKey", XydCreditLoanConstants.XYD_TEST_PUBLIC_KEY);

    private final XydCreditLoanService xydCreditLoanService;
    private final AlarmService alarmService;

    public XydCreditLoanThirdController(XydCreditLoanService xydCreditLoanService, AlarmService alarmService) {
        this.xydCreditLoanService = xydCreditLoanService;
        this.alarmService = alarmService;
    }

    /**
     * 2.2.4.1通知授信结果数据
     */
    @PostMapping("/notify/auth-credit")
    public void notifyAuthCredit(@RequestBody String body,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {
        // log.info("##notifyAuthCredit小雨点授信通知接口--小雨点callback：{}",body);
        String logPrefix = "小雨点授信通知";
        this.doWork(request, response, xydCreditLoanService::notifyAuthCredit, body, XydNotifyAuthCreditDto.class, logPrefix);
    }



    /**
     * 2.2.4.通知取消还款
     */
    @PostMapping("/notify/cancelRepayment")
    public void cancelRepayment(@RequestBody String body,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {
        // log.info("##cancelRepayment-通知取消还款--小雨点callback：{}",body);
        String logPrefix = "小雨点通知取消还款";
        this.doWork(request, response, xydCreditLoanService::cancelRepayment, body, XydNotifyCancelRepaymentDto.class, logPrefix);
    }


    /**
     * 2.2.2.1同步客户数据(申请授信小雨点反查)
     */
    @PostMapping("/merchantInfo/sync")
    public void merchantInfoSync(@RequestBody String body,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {
        // log.info("##merchantInfoSync--同步客户数据(申请授信小雨点反查)--小雨点callback：{}",body);
        String logPrefix = "同步客户数据(申请授信小雨点反查)";
        this.doWork(request, response, xydCreditLoanService::merchantInfoSync, body, XydMerchantInfoSyncReq.class, logPrefix);
    }

    /**
     * 2.2.3.1同步历史订单数据(申请授信小雨点反查)
     */
    @PostMapping("/historyOrderInfo/sync")
    public void historyOrderInfoSync(@RequestBody String body,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {

        String logPrefix = "同步历史订单数据(申请授信小雨点反查)";
        this.doWork(request, response, xydCreditLoanService::historyOrderInfoSync, body, XydHistoryOrderInfoSyncReq.class, logPrefix);
    }

    /**
     * 3.2.4.1校验订单有效
     */
    @PostMapping("/orderValid/verify")
    public void orderValidVerify(@RequestBody String body,
                                     HttpServletRequest request,
                                     HttpServletResponse response) {

        String logPrefix = "小雨点校验订单有效";
        this.doWork(request, response, xydCreditLoanService::orderValidVerify, body, XydOrderValidVerifyReq.class, logPrefix);
    }

    /**
     * 3.2.2.1放款获取订单信息
     */
    @PostMapping("/lending/orderInfo")
    public void lendingOrderInfo(@RequestBody String body,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {
        // log.info("##lendingOrderInfo--1放款获取订单信息--小雨点callback：{}",body);

        String logPrefix = "小雨点放款获取订单信息";
        this.doWork(request, response, xydCreditLoanService::lendingOrderInfo, body, XydLendingOrderInfoReq.class, logPrefix);
    }

    /**
     * 4.2.2.1通知还款结果
     */
    @PostMapping("/notify/repaymentResults")
    public void notifyRepaymentResults(@RequestBody String body,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {
        // log.info("##notifyRepaymentResults--1通知还款结果--小雨点callback：{}",body);

        String logPrefix = "小雨点通知还款结果";
        this.doWork(request, response, xydCreditLoanService::notifyRepaymentResults, body, XydNotifyRepaymentResultsReq.class, logPrefix);
    }

    /**
     * 通知放款结果
     */
    @PostMapping("/notify/loan-result")
    public void notifyLoanResult(@RequestBody String body,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {
        // log.info("##notifyLoanResult--通知放款结果--小雨点callback：{}",body);
        String logPrefix = "小雨点通知放款结果";
        this.doWork(request, response, xydCreditLoanService::notifyLoanResult, body, XydNotifyLoanResultReq.class, logPrefix);
    }

    /**
     * 通知锁定订单
     */
    @PostMapping("/notify/lock-order")
    public void notifyLockOrder(@RequestBody String body,
                                HttpServletRequest request,
                                HttpServletResponse response) {
        // log.info("##notifyLockOrder--通知锁定订单--小雨点callback：{}",body);
        String logPrefix = "小雨点通知锁定订单";
        this.doWork(request, response, xydCreditLoanService::notifyLockOrder, body, XydNotifyLockOrderReq.class, logPrefix);
    }

    /**
     * 2.1.3.1 同步结果
     */
    @PostMapping("/syncCreditNodeStatus")
    public void syncCreditNodeStatus(@RequestBody String body,
                                HttpServletRequest request,
                                HttpServletResponse response) {
        //log.info("##syncCreditNodeStatus--同步结果--小雨点 param：{}",body);
        String logPrefix = "小雨点同步结果";
        this.doWork(request, response, xydCreditLoanService::syncCreditNodeStatus, body, XydSyncCreditNodeStatusReq.class, logPrefix);
    }


    /**
     * 示例
     *
     * @param body
     * @param request
     * @param response
     */
    @PostMapping("/caseMethod")
    public void caseMethod(@RequestBody String body,
                           HttpServletRequest request,
                           HttpServletResponse response) {
        String logPrefix = "caseMethod";
        this.doWork(request, response, xydCreditLoanService::caseMethod, body, List.class, logPrefix);
    }

    private void makeXydResponse(HttpServletResponse response, String code, String msg, Object data) {
        Map<String, Object> respMap = new HashMap<>();
        respMap.put("code", code);
        respMap.put("message", msg);
        respMap.put("data", data);

        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        response.setCharacterEncoding("utf-8");

        String resBody = JSON.toJSONString(respMap);

        try {
            response.getWriter().print(resBody);
        } catch (Throwable t) {
            // ignore
        }
    }

    protected <T, R> void doWork(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Function<T, R> func,
                                 String body,
                                 Class<T> tClass,
                                 String logPrefix) {

        // 验签
        String logPrettyBody = body;
        try {
            logPrettyBody = StringUtils.isNotBlank(body) ? body.replaceAll("\\s", "") : body;
            log.info("xydCreditLoan {} request body:{}", logPrefix, logPrettyBody);
            JSONObject signJsonObj = getSignObj(request, body);
            boolean verifySuc = StringUtils.isNotBlank(signJsonObj.getString("sign")) &&
                    XydSignUtil.verifySign(signJsonObj.toJSONString(), XYD_RESPONSE_PUBLIC_KEY);
            if (!verifySuc) {

                alarmService.asyncAlarm("小雨点调支付中台接口验签失败", "XydCreditLoanThirdController.doWork.verifySign",
                        logPrefix + "失败", null);

                makeXydResponse(response, XydCreditLoanConstants.FAIL_CODE, "验签失败", null);
                return;
            }

        } catch (Exception e) {
            log.error("XydCreditLoan {} request validate error, body:{}", logPrefix, logPrettyBody, e);

            alarmService.asyncAlarm("小雨点调支付中台接口验签异常", "XydCreditLoanThirdController.doWork.verifySign",
                    logPrefix + "失败原因：" + e.getMessage(), logPrettyBody);

            makeXydResponse(response, XydCreditLoanConstants.FAIL_CODE, "验签异常", null);
            return;
        }

        // exec
        try {
            R result = func.apply(JSON.parseObject(body, tClass));
            makeXydResponse(response, XydCreditLoanConstants.SUCCESS_CODE, XydCreditLoanConstants.SUCCESS_MSG, result);
        } catch (Exception e) {
            log.error("XydCreditLoan {} exec error, body:{}", logPrefix, logPrettyBody, e);

            alarmService.asyncAlarm("小雨点调支付中台接口异常", "XydCreditLoanThirdController.doWork.apply",
                    logPrefix + "失败原因：" + e.getMessage(), logPrettyBody);

            if (e instanceof PaymentException) {
                PaymentException pe = (PaymentException) e;
                makeXydResponse(response, XydCreditLoanConstants.FAIL_CODE, pe.getErrMsg(), null);
                return;
            }
            makeXydResponse(response, XydCreditLoanConstants.FAIL_CODE, XydCreditLoanConstants.FAIL_MSG, null);
        }
    }

    private JSONObject getSignObj(HttpServletRequest request, String body) {
        String accessKey = request.getHeader(XydCreditLoanConstants.HEADER_ACCESSKEY);
        String sign = request.getHeader(XydCreditLoanConstants.HEADER_SIGN);
        String timestamp = request.getHeader(XydCreditLoanConstants.HEADER_TIMESTAMP);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("accessKey", accessKey);
        jsonObject.put("timestamp", timestamp);
        jsonObject.put("data", body);
        jsonObject.put("sign", sign);
        return jsonObject;
    }

}
